package com.lagou.sqlSession;

import com.lagou.pojo.Configuration;
import com.lagou.pojo.MappedStatement;
import com.lagou.utils.GenericTokenParser;
import com.lagou.utils.ParameterMapping;
import com.lagou.utils.ParameterMappingTokenHandler;

import java.lang.reflect.Field;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class simpleExecutor implements Executor {

    @Override
    public <E> List<E> query(Configuration configuration, MappedStatement statement, Object... params) throws Exception {
        //获取jdbc连接
        Connection connection = configuration.getDataSource().getConnection();
        //获取原始sql
        String sql = statement.getSql();
        //获取封装好的要发送的sql语句与参数
        BoundSql boundSql = boundSql(sql);
        PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSqlText());
        String paramterType = statement.getParamterType();
        String resultType = statement.getResultType();
        Class<?> paramterTypeClass = getClassType(paramterType);
        //对参数赋值
        List<ParameterMapping> parameterMappingList = boundSql.getParameterMappingList();
        for (int i = 0; i < parameterMappingList.size(); i++) {
            ParameterMapping parameterMapping = parameterMappingList.get(i);
            String content = parameterMapping.getContent();
            Field declaredField = paramterTypeClass.getDeclaredField(content);
            declaredField.setAccessible(true);
            Object o = declaredField.get(params[0]);
            preparedStatement.setObject(i + 1, o);
        }
        Class<?> resultTypeClass = getClassType(resultType);
        ResultSet resultSet = preparedStatement.executeQuery();
        ArrayList<Object> objects = new ArrayList<>();
       // 遍历结果集并封装返回
        while (resultSet.next()) {
            Object o = resultTypeClass.newInstance();
            ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
            for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
                String columnName = resultSetMetaData.getColumnName(i);
                Object object = resultSet.getObject(columnName);
                /*PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columnName, resultTypeClass);
                Method writeMethod = propertyDescriptor.getWriteMethod();
                writeMethod.invoke(o, object);*/
                Field declaredField = resultTypeClass.getDeclaredField(columnName);
                declaredField.setAccessible(true);
                declaredField.set(o, object);
            }

            objects.add(o);
        }
        return (List<E>) objects;
    }

    @Override
    public Integer update(Configuration configuration, MappedStatement statement, Object... params) throws Exception {
        PreparedStatement preparedStatement = getPreparedStatement(configuration, statement, params[0]);
        int i = preparedStatement.executeUpdate();
        return i;
    }

    @Override
    public Integer delete(Configuration configuration, MappedStatement statement, Object... params) throws Exception {
        PreparedStatement preparedStatement = getPreparedStatement(configuration, statement, params[0]);
        int i = preparedStatement.executeUpdate();
        return i;
    }

    private PreparedStatement getPreparedStatement(Configuration configuration, MappedStatement statement, Object param) throws SQLException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
        Connection connection = configuration.getDataSource().getConnection();
        String sql = statement.getSql();
        BoundSql boundSql = boundSql(sql);
        PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSqlText());
        String paramterType = statement.getParamterType();
        Class<?> paramterTypeClass = getClassType(paramterType);
        List<ParameterMapping> parameterMappingList = boundSql.getParameterMappingList();
        for (int i = 0; i < parameterMappingList.size(); i++) {
            ParameterMapping parameterMapping = parameterMappingList.get(i);
            String content = parameterMapping.getContent();
            Field declaredField = paramterTypeClass.getDeclaredField(content);
            declaredField.setAccessible(true);
            Object o = declaredField.get(param);
            preparedStatement.setObject(i + 1, o);
        }
        return preparedStatement;
    }


    private Class<?> getClassType(String paramterType) throws ClassNotFoundException {
        Class<?> aClass = Class.forName(paramterType);
        return aClass;
    }

    private BoundSql boundSql(String sql) {
       //标记解析器
        ParameterMappingTokenHandler parameterMappingTokenHandler = new ParameterMappingTokenHandler();
        GenericTokenParser genericTokenParser = new GenericTokenParser("#{", "}", parameterMappingTokenHandler);
        //封装参数集合到List中
        List<ParameterMapping> parameterMappings = parameterMappingTokenHandler.getParameterMappings();
        //封装发送的sql与参数方便在调用中使用
        BoundSql boundSql = new BoundSql(genericTokenParser.parse(sql), parameterMappings);
        return boundSql;
    }

}
